#![cfg_attr(not(debug_assertions), windows_subsystem = "windows")]
#![allow(non_snake_case)]
#![allow(non_camel_case_types)]
#[allow(unused_imports)]
use fltk::{
    self,
    app::{App, Sender},
    button,
    prelude::{GroupExt, TableExt, WidgetBase, WidgetExt, WindowExt},
    window::{DoubleWindow, Window},
    *,
};
use std::{
    cell::RefCell, collections::HashMap, ffi::OsString, os::windows::prelude::OsStrExt, rc::Rc,
};
#[allow(unused_imports)]
use windows::{
    Win32::Foundation::*,
    Win32::{Security::*, Storage::FileSystem::*, System::Time::*, System::IO::*},
};

use chrono::prelude::*;

//
struct ftime;
// //
// impl Default for ftime {
//     fn default() -> Self {
//         // ftime::new(1970,1,1,0,0,0)
//     }
// }
impl ftime {
    // /// 创建一个ftime
    // fn new(year: i32, month: u32, day: u32, hour: u32, min: u32, sec: u32) -> Self {
    //     ftime {
    //         year,
    //         month,
    //         day,
    //         hour,
    //         min,
    //         sec,
    //     }
    // }
    //
    fn unix2ftime(t: i64) -> i64 {
        // let mut y = self.year;
        // if y < 1970 {
        //     y = 1970;
        // }
        // let base = Local.ymd(y, self.month, self.day)
        //     .and_hms(self.hour, self.min, self.sec)
        //     .timestamp();
        //返回时间
        (11644473600 + t) * (10i64.pow(7))
    }
    //

    // //
    // fn ftime2unix(ft: i64) -> i64 {
    //     let t = (ft as f64) / ((10i64.pow(7) as f64) * 1.0).round() - 11644473600f64;

    //     t as i64
    // }
    //  //
    //  fn timestamp(&self)->i64{
    //     Local.ymd(self.year, self.month, self.day)
    //     .and_hms(self.hour, self.min, self.sec)
    //     .timestamp()
    //  }
    //
    fn unix2local(stamp: i64) -> DateTime<Local> {
        Local.timestamp(stamp, 0)
    }
}

//
struct fop<'a>(&'a str);

impl<'a> fop<'a> {
    fn new(f: &'a str) -> Self {
        Self(f)
    }
    ///获取文件时间，返回创建，修改，访问时间
    fn getFileTime(&self) -> Result<(i64, i64, i64), &str> {
        //默认返回数值
        let mut r: Result<(i64, i64, i64), &str> = Err("unvalid");
        unsafe {
            let f = OsString::from(self.0);
            // f.push("\0");
            let result: Vec<u16> = f.encode_wide().collect();
            //    let mut result = self.0.to_owned();
            //    result.push('\0');
            //    println!("{:?}",result);
            let hfile = CreateFileW(
                PWSTR(result.as_ptr() as _),
                FILE_GENERIC_READ | FILE_GENERIC_WRITE,
                FILE_SHARE_NONE,
                std::ptr::null(),
                OPEN_EXISTING,
                FILE_ATTRIBUTE_NORMAL,
                &None,
            );
            //打开文件成功
            if !hfile.is_invalid() {
                //读取ftime
                let mut ft1 = FILETIME::default();
                let mut ft2 = FILETIME::default();
                let mut ft3 = FILETIME::default();
                GetFileTime(hfile, &mut ft1 as _, &mut ft2 as _, &mut ft3 as _);

                let mut stUTC = SYSTEMTIME::default();
                let mut stLOCAL = SYSTEMTIME::default();
                //
                FileTimeToSystemTime(&mut ft1 as _, &mut stUTC as _);
                SystemTimeToTzSpecificLocalTime(
                    std::ptr::null(),
                    &mut stUTC as _,
                    &mut stLOCAL as _,
                );

                let fc = Local
                    .ymd(stLOCAL.wYear as _, stLOCAL.wMonth as _, stLOCAL.wDay as _)
                    .and_hms_milli(
                        stLOCAL.wHour as _,
                        stLOCAL.wMinute as _,
                        stLOCAL.wSecond as _,
                        stLOCAL.wMilliseconds as _,
                    )
                    .timestamp();

                FileTimeToSystemTime(&mut ft2 as _, &mut stUTC as _);
                SystemTimeToTzSpecificLocalTime(
                    std::ptr::null(),
                    &mut stUTC as _,
                    &mut stLOCAL as _,
                );

                let fa = Local
                    .ymd(stLOCAL.wYear as _, stLOCAL.wMonth as _, stLOCAL.wDay as _)
                    .and_hms_milli(
                        stLOCAL.wHour as _,
                        stLOCAL.wMinute as _,
                        stLOCAL.wSecond as _,
                        stLOCAL.wMilliseconds as _,
                    )
                    .timestamp();

                FileTimeToSystemTime(&mut ft3 as _, &mut stUTC as _);
                SystemTimeToTzSpecificLocalTime(
                    std::ptr::null(),
                    &mut stUTC as _,
                    &mut stLOCAL as _,
                );

                let fm = Local
                    .ymd(stLOCAL.wYear as _, stLOCAL.wMonth as _, stLOCAL.wDay as _)
                    .and_hms_milli(
                        stLOCAL.wHour as _,
                        stLOCAL.wMinute as _,
                        stLOCAL.wSecond as _,
                        stLOCAL.wMilliseconds as _,
                    )
                    .timestamp();
                //
                // let ft1: i64 =
                //     (ft1.dwLowDateTime as i64) | (((ft1.dwHighDateTime as i64) << 32i64) as i64);
                // let fc = ftime::ftime2unix(ft1);
                // //
                // let ft2: i64 =
                //     (ft2.dwLowDateTime as i64) | (((ft2.dwHighDateTime as i64) << 32i64) as i64);
                // let fa = ftime::ftime2unix(ft2);
                // //
                // let ft3: i64 =
                //     (ft3.dwLowDateTime as i64) | (((ft3.dwHighDateTime as i64) << 32i64) as i64);
                // let fm = ftime::ftime2unix(ft3);
                // println!("{:?}",ft);

                r = Ok((fc, fa, fm));
                //
                CloseHandle(hfile);
            }
        }
        r
    }

    /// 设置文件时间的信息
    fn setFileTime(&self, c: i64, m: i64, a: i64) {
        let fc = ftime::unix2ftime(c);
        let fm = ftime::unix2ftime(m);
        let fa = ftime::unix2ftime(a);
        //
        unsafe {
            //打开文件句柄
            let f = OsString::from(self.0);
            // f.push("\0");
            let result: Vec<u16> = f.encode_wide().collect();
            //    let mut result = self.0.to_owned();
            //    result.push('\0');
            //    println!("{:?}",result);
            let hfile = CreateFileW(
                PWSTR(result.as_ptr() as _),
                FILE_GENERIC_READ | FILE_GENERIC_WRITE,
                FILE_SHARE_NONE,
                std::ptr::null(),
                OPEN_EXISTING,
                FILE_ATTRIBUTE_NORMAL,
                &None,
            );
            // println!("---------{:?}",hfile);
            //打开文件成功
            if !hfile.is_invalid() {
                //读取ftime
                let mut ft1 = FILETIME::default();
                let mut ft2 = FILETIME::default();
                let mut ft3 = FILETIME::default();
                // GetFileTime(hfile,&mut ft1 as _,&mut ft2 as _,&mut ft3 as _ );
                //
                ft1.dwLowDateTime = fc as u32;
                ft1.dwHighDateTime = (fc >> 32u64) as u32;
                //
                ft2.dwLowDateTime = fa as u32;
                ft2.dwHighDateTime = (fa >> 32u64) as u32;
                //
                ft3.dwLowDateTime = fm as u32;
                ft3.dwHighDateTime = (fm >> 32u64) as u32;

                SetFileTime(hfile, &ft1 as _, &ft2 as _, &ft3 as _);
                CloseHandle(hfile);
            }
        }
    }
}

use fltk::{enums::*, prelude::*, *};
const WIDTH: i32 = 480;
const HEIGHT: i32 = 200;

struct timeCard {
    frm: window::Window,
    //input作为成员
    inputa: input::Input,
    inputm: input::Input,
    inputc: input::Input,
    f: String,
    regexdt: regex::Regex,
}
//事件改变
const TimeChanged: i32 = 1000;

impl timeCard {
    fn new(s: Sender<String>, w: i32, h: i32) -> Self {
        let win = window::Window::default().with_size(w, h);
        //封装
        //
        let flCol = group::Flex::default()
            .with_type(group::FlexType::Column)
            .with_size(w, h - 40);
        frame::Frame::default().with_label("创建时间");
        //创建一个lineEdit
        let mut lineEditC = input::Input::default();
        frame::Frame::default().with_label("修改时间");
        let mut lineEditM = input::Input::default();
        frame::Frame::default().with_label("访问时间");
        let mut lineEditA = input::Input::default();
        // lineEditA.set_callback(cb)
        // flCol.set_pad(0);
        flCol.end();
        //
        let mut tip = frame::Frame::default().with_size(w, 30);
        tip.set_label("时间数据,自动保存");
        tip.set_label_color(Color::from_hex(0x123456));
        tip.below_of(&flCol, 1);
        //
        win.end();
        //设置触发条件
        let sa = s.clone();
        lineEditA.set_trigger(CallbackTrigger::Changed);
        lineEditA.set_callback(move |_| {
            // app::handle_main(TimeChanged).unwrap();
            sa.send("dummy".to_string());
        });
        //
        let sm = s.clone();
        lineEditM.set_trigger(CallbackTrigger::Changed);
        lineEditM.set_callback(move |_| {
            // app::handle_main(TimeChanged).unwrap();
            sm.send("dummy".to_string());
        });
        //
        let sc = s.clone();
        lineEditC.set_trigger(CallbackTrigger::Changed);
        lineEditC.set_callback(move |_| {
            // app::handle_main(TimeChanged).unwrap();
            sc.send("dummy".to_string());
        });
        //
        //匹配年月日时分秒
        let regexdt =
            regex::Regex::new(r#"^\d{4}-\d{1,2}-\d{1,2}\s+\d{1,2}:\d{1,2}:\d{1,2}"#).unwrap();
        Self {
            frm: win,
            inputa: lineEditA,
            inputc: lineEditC,
            inputm: lineEditM,
            f: "".to_string(),
            regexdt,
        }
    }
    //输入文件名，自动填充时间
    fn loadFile(&mut self, f: &str) {
        //保存接收文件
        self.f = f.to_owned();
        //构造
        let tm = fop::new(f);
        let (c, a, m) = tm.getFileTime().unwrap();
        // println!("{},{},{}",a,c,m);
        //转换时间戳到时间
        let atm = ftime::unix2local(a);
        // println!("{}",atm.to_string());
        let atm = atm.format("%F %T");
        self.inputa.set_value(&atm.to_string());

        //转换时间戳到时间
        let ctm = ftime::unix2local(c);
        // println!("{}",atm.to_string());
        let ctm = ctm.format("%F %T");
        self.inputc.set_value(&ctm.to_string());

        //转换时间戳到时间
        let mtm = ftime::unix2local(m);
        let mtm = mtm.format("%F %T");
        // println!("{}",atm.format("%F %T"));
        self.inputm.set_value(&mtm.to_string());
    }

    //修改后，自动保存时间
    fn saveFile(&mut self) {
        let tmf = fop::new(&self.f);
        //处理input c
        let tmc = self.inputc.value();
        let tmm = self.inputc.value();
        let tma = self.inputc.value();
        //采用正则校验通过之后进行转换
        if self.regexdt.is_match(&tmc) && self.regexdt.is_match(&tma) && self.regexdt.is_match(&tmm)
        {
            //同时匹配
            println!("日期格式不匹配");
        } else {
            return;
        }

        let tmc = NaiveDateTime::parse_from_str(&tmc, "%Y-%m-%d %H:%M:%S");
        if tmc.is_err() {
            // dialog::message_default("时间格式错误");
            println!("{:?}", tmc);
            return;
        }
        //纠正到东八区
        let tmc = FixedOffset::east(8 * 3600).from_utc_datetime(&tmc.unwrap());
        let tmc = tmc.timestamp();

        //处理input m

        let tmm = NaiveDateTime::parse_from_str(&tmm, "%Y-%m-%d %H:%M:%S");
        if tmm.is_err() {
            // dialog::message_default("时间格式错误");
            println!("{:?}", tmm);
            return;
        }
        //纠正到东八区
        let tmm = FixedOffset::east(8 * 3600).from_utc_datetime(&tmm.unwrap());
        let tmm = tmm.timestamp();

        //处理input a
        let tma = NaiveDateTime::parse_from_str(&tma, "%Y-%m-%d %H:%M:%S");
        if tma.is_err() {
            // dialog::message_default("时间格式错误");
            println!("{:?}", tma);
            return;
        }
        //纠正到东八区
        let tma = FixedOffset::east(8 * 3600).from_utc_datetime(&tma.unwrap());
        let tma = tma.timestamp();
        //输出调试信息
        println!("{}", "success");
        tmf.setFileTime(tmc, tmm, tma)
        //获取控件事件，判断合法性
    }
}
widget_extends!(timeCard, window::Window, frm);

// Needed to store cell information during the draw_cell call
#[derive(Default)]
struct CellData {
    row: i32, // row
    col: i32, // column
    x: i32,
    y: i32,
    w: i32,
    h: i32,
}

impl CellData {
    pub fn select(&mut self, row: i32, col: i32, x: i32, y: i32, w: i32, h: i32) {
        self.row = row;
        self.col = col;
        self.x = x;
        self.y = y;
        self.w = w;
        self.h = h;
    }
}
pub struct MyTable {
    table: table::TableRow,
    cell: Rc<RefCell<CellData>>,
    data: Rc<RefCell<Vec<Vec<String>>>>,
    hsdata: Rc<RefCell<HashMap<String, String>>>,
    // curf:Rc<RefCell<String>>,
    // sender:Sender<String>
}

// struct MyEvent;
// impl MyEvent {
//     const FILENAMECHANGE:i32 = 1000;
// }

impl MyTable {
    pub fn new(mut inp: input::Input, sender: Sender<String>, w: i32, h: i32) -> Self {
        let mut table = table::TableRow::default()
            .with_size(w, h)
            .center_of_parent();
        let data = Rc::from(RefCell::from(vec![vec![String::from(""); 1]; 10]));
        //
        // data.borrow_mut()[0][0]="".to_string();
        let cell = Rc::from(RefCell::from(CellData::default()));
        let hsdata = Rc::new(RefCell::from(HashMap::default()));
        //
        // let curf = Rc::new(RefCell::new("".to_string()));
        table.set_rows(10);
        table.set_row_header(false);
        table.set_row_resize(false);
        table.set_cols(1);
        table.set_col_header(false);
        table.set_col_width_all(w);
        table.set_col_resize(false);
        table.set_type(table::TableRowSelectMode::Single);
        table.end();

        let cell_c = cell.clone();
        let data_c = data.clone();

        // Called when the table is drawn then when it's redrawn due to events
        table.draw_cell(move |t, ctx, row, col, x, y, w, h| match ctx {
            table::TableContext::StartPage => draw::set_font(enums::Font::Helvetica, 14),
            table::TableContext::ColHeader => {
                Self::draw_header(&format!("{}", (col + 65) as u8 as char), x, y, w, h)
            } // Column titles
            table::TableContext::RowHeader => {
                Self::draw_header(&format!("{}", row + 1), x, y, w, h)
            } // Row titles
            table::TableContext::Cell => {
                if t.is_selected(row, col) {
                    cell_c.borrow_mut().select(row, col, x, y, w, h); // Captures the cell information
                                                                      // println!("{}",&data_c.borrow_mut()[row as usize][col as usize]);
                }
                Self::draw_data(
                    &data_c.borrow()[row as usize][col as usize].to_string(),
                    x,
                    y,
                    w,
                    h,
                    t.is_selected(row, col),
                );
            }
            table::TableContext::EndPage => {
                t.redraw();
            }
            _ => (),
        });

        let cell_c = cell.clone();
        let data_c = data.clone();
        //使用updata函数更新数值的时候对他不产生影响，原因可能是拥有的指针，通过refcell的swap函数可以改变
        let hsdata_c = hsdata.clone();
        // let curf_c =curf.clone();
        //

        table.handle(move |t, ev| match ev {
            // Event::Push will happen before the focus is moved,
            // thus giving the previous coordinates.
            // Event::Released gives an accurate position
            enums::Event::Released => {
                let c = cell_c.borrow();
                inp.resize(c.x, c.y, c.w, c.h);
                inp.set_value(&data_c.borrow_mut()[c.row as usize][c.col as usize]);
                inp.hide();
                inp.take_focus().ok();
                inp.redraw();
                if t.is_selected(c.row, c.col) {
                    let f: &String =
                        &hsdata_c.borrow()[&data_c.borrow_mut()[c.row as usize][c.col as usize]];
                    // println!("{}",f);
                    let f_c = f.clone();
                    // curf_c.swap(&RefCell::new(f_c));
                    //发送事件
                    // app::handle_main(MyEvent::FILENAMECHANGE).unwrap();
                    sender.send(f_c);
                }
                true
            }
            _ => false,
        });

        Self {
            table,
            data,
            cell,
            hsdata,
        }
    }

    pub fn redraw(&mut self) {
        self.table.redraw()
    }

    fn draw_header(txt: &str, x: i32, y: i32, w: i32, h: i32) {
        draw::push_clip(x, y, w, h);
        draw::draw_box(
            enums::FrameType::ThinUpBox,
            x,
            y,
            w,
            h,
            enums::Color::FrameDefault,
        );
        draw::set_draw_color(enums::Color::Black);
        draw::set_font(enums::Font::Helvetica, 14);
        draw::draw_text2(txt, x, y, w, h, enums::Align::Center);
        draw::pop_clip();
    }

    // The selected flag sets the color of the cell to a grayish color, otherwise white
    fn draw_data(txt: &str, x: i32, y: i32, w: i32, h: i32, selected: bool) {
        draw::push_clip(x, y, w, h);
        if selected {
            draw::set_draw_color(enums::Color::from_u32(0x00D3_D3D3));
        } else {
            draw::set_draw_color(enums::Color::White);
        }
        draw::draw_rectf(x, y, w, h);
        draw::set_draw_color(enums::Color::Black);
        draw::set_font(enums::Font::Helvetica, 14);
        draw::draw_text2(txt, x + 10, y, w, h, enums::Align::Left);
        draw::draw_focus_rect(x, y, w, h);
        draw::pop_clip();
    }

    //更新data
    pub fn updateData(&mut self, newData: Vec<Vec<String>>, hs: HashMap<String, String>) {
        self.data.swap(&RefCell::from(newData));
        self.hsdata.swap(&RefCell::from(hs));
        // *Rc::get_mut(&mut self.hsdata).unwrap() = hs;
        // self.hsdata = Rc::new(hs);
        self.redraw();
    }
}

widget_extends!(MyTable, table::TableRow, table);
fn main() {
    let app = app::App::default().with_scheme(app::Scheme::Gtk);
    let mut wind = window::Window::default()
        .with_size(WIDTH, HEIGHT)
        .center_screen();
    wind.set_color(Color::White);
    //创建flex布局，左右分开
    let mut flRow = group::Flex::default()
        .with_size(WIDTH - 10, HEIGHT - 10)
        .center_of_parent();
    let mut b1 = button::Button::default().with_label("添加文件");

    let mut flRow_c = flRow.clone();
    //
    let (s, r) = app::channel::<String>();
    // let mut mtb;
    let s_c = s.clone();
    b1.set_callback(move |btn| {
        // dialog::message(app::get_mouse().0,app::get_mouse().1, "shushu");
        let mut fileSee = dialog::NativeFileChooser::new(dialog::FileDialogType::BrowseMultiFile);
        fileSee.show();
        let mut VecVecString: Vec<Vec<String>> = vec![vec![]];
        let mut hsdata = HashMap::new();
        //上述的语句会有个空，使用clear函数清理
        VecVecString.clear();
        //显示获取到多个文件名-转到table表中进行显示
        println!("{:?}", fileSee.filenames());
        for v in fileSee.filenames() {
            // println!("{:?}",v);
            //保存文件名
            let keyFile = String::from(v.file_name().unwrap().to_string_lossy());
            hsdata.insert(keyFile.clone(), v.to_string_lossy().to_string());
            VecVecString.push(vec![keyFile]);
        }
        btn.hide();
        let mut mtb = MyTable::new(input::Input::default(), s_c.clone(), 260, 200);
        mtb.end();
        mtb.table.set_rows(VecVecString.len() as i32);
        mtb.table.set_cols(1);
        mtb.updateData(VecVecString, hsdata);
        flRow_c.remove_by_index(0);
        // mtb.set_size(260, 200);
        flRow_c.insert(&mtb.table, 0);
        mtb.redraw();
    });
    let mut b2 = timeCard::new(s.clone(), 220, 200);
    //
    flRow.set_size(&b1, 260);
    flRow.end();

    wind.end();
    wind.show();
    wind.set_label("文件时间修改器");
    // app.run().unwrap();

    //必须经过消息循环进行中转
    //可能还有其他办法
    while app.wait() {
        if let Some(v) = r.recv() {
            // println!("..........{}",&v);
            if v != "dummy" {
                //过滤掉
                b2.loadFile(&v);
            } else {
                b2.saveFile();
            }
        }
        //
    }
}
